package com.arashivision.wifisdk;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static android.content.Context.WIFI_SERVICE;
import static com.arashivision.wifisdk.Wifi.ConfigSec;

public class WifiSdkImplement
{
    private static final String TAG = "OneWifiSdk";
    private WifiManager mWifiManager;

    private Context mContext;
    private boolean mRegister;

    private long mScanDurationMs;
    private long mScanStart;
    private final WifiSdkCallback mWifiSdkCallback;
    private final int mNumOpenNetworksKept;
    private Handler mHandler;
    private Handler mCallbackHandler;
    private boolean mDebug;

    public WifiSdkImplement(final Looper looper,final Context context, final WifiSdkCallback callback,final Handler callbackHandler)
    {
        mHandler = new Handler(looper);
        mContext = context.getApplicationContext();
        mWifiManager = (WifiManager) mContext.getSystemService(WIFI_SERVICE);

        final IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        mContext.registerReceiver(mReceiver, filter);

        if(callbackHandler != null)
        {
            mCallbackHandler = callbackHandler;
        }
        else
        {
            mCallbackHandler = mHandler;
        }
        mRegister = true;

        mNumOpenNetworksKept =  Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, 10);

        mWifiSdkCallback = callback;
        logd("mNumOpenNetworksKept " + mNumOpenNetworksKept);
    }

//    @android.support.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
//    public boolean checkScanAvail()
//    {
//         return mWifiManager.isScanAlwaysAvailable();
//    }

    private void logd(String msg)
    {
        if(mDebug)
            Log.d(TAG,msg);
    }

    private void loge(String msg)
    {
        if(mDebug)
            Log.e(TAG,msg);
    }

    public void setEnableDebug(boolean bState)
    {
        mDebug = bState;
    }

    public void startScan(long scanDuration)
    {
        mScanDurationMs = scanDuration;
        mScanStart = System.nanoTime();
        mWifiManager.startScan();
    }

    public int calculateSignal(int rssi, int numLevels)
    {
        return WifiManager.calculateSignalLevel(rssi, numLevels);
    }

    /**
     * 排除重复
     * @param scanResults 带处理的数据
     * @return 去重数据
     */
    private ArrayList<ScanResult> excludeRepetition(List<ScanResult> scanResults) {
        HashMap<String, ScanResult> hashMap = new HashMap<>();

        for (ScanResult scanResult : scanResults) {
            String ssid = scanResult.SSID;

            if (TextUtils.isEmpty(ssid)) {
                continue;
            }

            ScanResult tempResult = hashMap.get(ssid);
            if (null == tempResult) {
                hashMap.put(ssid, scanResult);
                continue;
            }

            if (calculateSignal(tempResult.level, 100) < calculateSignal(scanResult.level, 100)) {
                hashMap.put(ssid, scanResult);
            }
        }

        ArrayList<ScanResult> results = new ArrayList<>();
        for (Map.Entry<String, ScanResult> entry : hashMap.entrySet()) {
            results.add(entry.getValue());
        }

        return results;
    }

    public void stopScan()
    {
        mScanDurationMs = 0;
    }

    public void release()
    {
        mScanDurationMs = 0;
        mHandler = null;
        mCallbackHandler = null;
        if(mRegister)
        {
            mContext.unregisterReceiver(mReceiver);
            mRegister = false;
        }
    }

    public boolean getWifiState()
    {
        return mWifiManager.isWifiEnabled();
    }

    public void openWifi()
    {
        if(!mWifiManager.isWifiEnabled())
        {
            mWifiManager.setWifiEnabled(true);
        }
    }

    public void closeWifi()
    {
        if(mWifiManager.isWifiEnabled())
        {
            mWifiManager.setWifiEnabled(false);
        }
    }

    public WifiInfo getConnectWifiInfo()
    {
        WifiInfo mInfo= mWifiManager.getConnectionInfo();
        if(mInfo != null)
        {
            logd("connect ssid " + mInfo.getSSID() + " bssid " + mInfo.getBSSID());
        }
        else
        {
            logd("connect ssid null");
        }
        return mInfo;
    }

    private final WifiConfiguration getWifiResultConfig(ScanResult result)
    {
        final String security = ConfigSec.getScanResultSecurity(result);
        final WifiConfiguration config = Wifi.getWifiConfiguration(mWifiManager, result, security);
        return config;
    }

    public void forgetWifiResult(final ScanResult result)
    {
        boolean bRes = false;
        final WifiConfiguration config = getWifiResultConfig(result);
        if(config != null) {
            bRes = mWifiManager.removeNetwork(config.networkId)
                    && mWifiManager.saveConfiguration();

            Log.d(TAG,"networkId " + config.networkId + " bRes " + bRes);
        }
        else
        {
           loge("wifi never connected");
        }
        if(!bRes) {
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onForgetFail(result);
                }
            });
        }
        else
        {
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onForgetSuc(result);
                }
            });
        }
    }

    private void runOnCBHandler(final Runnable runnable)
    {
        if(mCallbackHandler != null)
        {
            if(mCallbackHandler.getLooper() == Looper.myLooper())
            {
                runnable.run();
            }
            else
            {
                mCallbackHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        runnable.run();
                    }
                });
            }
        }
    }

    public void changePwd(final ScanResult result,final String newPwd)
    {
        final WifiConfiguration config = getWifiResultConfig(result);

        ConfigSec.setupSecurity(config, ConfigSec.getWifiConfigurationSecurity(config), newPwd);
        final int networkId = mWifiManager.updateNetwork(config);
        logd("updateNetwork networkId " + networkId + " old id "+ config.networkId);
        runOnCBHandler(new Runnable()
        {
            @Override
            public void run()
            {
                if(networkId == -1) {
                    mWifiSdkCallback.changeWifiPwdFail(result);
                }
                else
                {
                    mWifiSdkCallback.changeWifiPwdSuc(result);
                }
            }
        });
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            final String action = intent.getAction();
            logd(" action " + action);
            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
            {
                if(mHandler != null)
                {
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            if(System.nanoTime() < (mScanDurationMs + mScanStart))
                            {
                                mWifiManager.startScan();
                            }
                        }
                    });
                }

                runOnCBHandler(new Runnable()
                {
                    @Override
                    public void run()
                    {
                       mWifiSdkCallback.onScanResult(excludeRepetition(mWifiManager.getScanResults()));
                    }
                });
            }
        }
    };

    private boolean isAdHoc(final ScanResult scanResule) {
        logd(" scanResule.capabilities " + scanResule.capabilities);
        return scanResule.capabilities.indexOf("IBSS") != -1;
    }

    public boolean isConnectWifi(ScanResult result)
    {
        logd( "isCurrentConnectWifi " + result.SSID);
        final WifiConfiguration config = getWifiResultConfig(result);
        final boolean isCurrentNetwork_ConfigurationStatus = config.status == WifiConfiguration.Status.CURRENT;
        final WifiInfo info = mWifiManager.getConnectionInfo();
        final boolean isCurrentNetwork_WifiInfo = info != null
                && android.text.TextUtils.equals(info.getSSID(), result.SSID)
                && android.text.TextUtils.equals(info.getBSSID(), result.BSSID);
        return (isCurrentNetwork_ConfigurationStatus || isCurrentNetwork_WifiInfo);
    }

    public void connectWithPwd(final ScanResult result,final String pwd)
    {
        logd("connectWithPwd " + result.SSID + " pwd " + pwd);
        boolean connResult;
        final String security = ConfigSec.getScanResultSecurity(result);

        if (Wifi.ConfigSec.isOpenNetwork(security))
        {
            connResult = Wifi.connectToNewNetwork(mContext, mWifiManager, result, null, mNumOpenNetworksKept);
        }
        else
        {
            connResult = Wifi.connectToNewNetwork(mContext, mWifiManager, result, pwd, mNumOpenNetworksKept);
        }

        if(connResult)
        {
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onConnectSuc(result);
                }
            });
        }
        else
        {
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onConnectFail(result);
                }
            });
        }
    }

    public void connect(final ScanResult result)
    {
        if(isAdHoc(result)) {
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onNotSupport(result);
                }
            });
            return;
        }

        final String security = ConfigSec.getScanResultSecurity(result);
        final WifiConfiguration config = Wifi.getWifiConfiguration(mWifiManager, result, security);
        if(config == null) {
           logd(" new wifi " + result.SSID);
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    mWifiSdkCallback.onConnectRequirePwd(result);
                }
            });
        }
        else
        {
            final boolean connResult = Wifi.connectToConfiguredNetwork(mContext, mWifiManager, config, false);
            runOnCBHandler(new Runnable()
            {
                @Override
                public void run()
                {
                    if(connResult)
                    {
                        mWifiSdkCallback.onConnectSuc(result);
                    }
                    else
                    {
                        mWifiSdkCallback.onConnectFail(result);
                    }
                }
            });
        }
    }
}